package com.xmy.study.config;

import com.xmy.study.filters.CROSUserFilter;
import com.xmy.study.filters.ShiroLoginFilter;
import com.xmy.study.filters.ShiroPermissionFilter;
import com.xmy.study.shiro.realm.AdminRealm;
import com.xmy.study.shiro.session.CustomSessionManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

//@Configuration
public class ShiroConfiguration {

    //1.创建realm
    @Bean
    public AdminRealm getRealm() {
        return new AdminRealm();
    }

    //2.创建安全管理器
    @Bean
    public SecurityManager getSecurityManager(AdminRealm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);

        //将自定义的会话管理器注册到安全管理器中
        securityManager.setSessionManager(sessionManager());
        //将自定义的redis缓存管理器注册到安全管理器中
        securityManager.setCacheManager(cacheManager());

        return securityManager;
    }

    //3.配置shiro的过滤器工厂

    /**
     * 再web程序中，shiro进行权限控制全部是通过一组过滤器集合进行控制
     *
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        //1.创建过滤器工厂
        ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
        //2.设置安全管理器
        filterFactory.setSecurityManager(securityManager);
        //3.通用配置（跳转登录页面，为授权跳转的页面）
        //filterFactory.setLoginUrl("/api/autherror?code=1");//跳转url地址
        //filterFactory.setUnauthorizedUrl("/api/autherror?code=2");//未授权的url
        //4.设置过滤器集合

        /**
         * 设置跨域
         */
        Map<String, Filter> filterFactoryFilters = filterFactory.getFilters();
        filterFactoryFilters.put("authc", new CROSUserFilter());
        filterFactory.setFilters(filterFactoryFilters);

        /**
         * 设置所有的过滤器：有顺序map
         *     key = 拦截的url地址
         *     value = 过滤器类型
         *
         */
        Map<String,String> filterMap = new LinkedHashMap<>();
        //anon匿名访问
        //filterMap.put("/user/home","anon");//当前请求地址可以匿名访问
        filterMap.put("/api/admin/auth/login","anon");

        filterMap.put("/swagger-resources/**","anon");
        filterMap.put("/webjars/**","anon");
        filterMap.put("/swagger-ui/**","anon");//访问地址：swagger-ui/index.html
        //注册后才能访问
        filterMap.put("/**","authc");

        /**
         * 自定义过滤器，未登陆返回json格式
         */
        Map<String, Filter> filters = new LinkedHashMap<>();
        filters.put("authc",getShiroLoginFilter());
        filters.put("perms",getShiroPermissionFilter());
        filterFactory.setFilters(filters);

        //具有某中权限才能访问
        // 使用过滤器的形式配置请求地址的依赖权限
        //filterMap.put("/user/home","perms[user-home]"); //不具备指定的权限，跳转到setUnauthorizedUrl地址
        //使用过滤器的形式配置请求地址的依赖角色
        //filterMap.put("/user/home","roles[系统管理员]");
        filterFactory.setFilterChainDefinitionMap(filterMap);

        return filterFactory;
    }


    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;

    /**
     * 1.redis的控制器，操作redis
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        //redisManager.setTimeout(1000 *60* 60*24);
        return redisManager;
    }

    /**
     * 2.sessionDao
     */
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        sessionDAO.setRedisManager(redisManager());
        sessionDAO.setExpire(60* 60*24);
        return sessionDAO;
    }

    /**
     * 3.会话管理器
     */
    public DefaultWebSessionManager sessionManager() {
        CustomSessionManager sessionManager = new CustomSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        // 设置session过期时间3600s
        Long timeOut = 1000L * 60 * 60 * 24;
        sessionManager.setGlobalSessionTimeout(timeOut);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionIdCookieEnabled(true);
        return sessionManager;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * 4.缓存管理器
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    public ShiroLoginFilter getShiroLoginFilter(){
        return new ShiroLoginFilter();
    }

    public ShiroPermissionFilter getShiroPermissionFilter(){
        return new ShiroPermissionFilter();
    }



    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    //开启对shior注解的支持
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


}
